package org.example.threadorder;

import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.example.utils.Sleeper;

import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.ReentrantLock;

/**
 * @author zhengdp
 * @Description 线程顺序控制(Park & UnPark) 交替输出abc
 * @Date 2022/11/9 22:24
 * @Created by zhengdp
 */
@Slf4j(topic = "c.ThreadOrderReentrantLock")
public class ThreadOrderReentrantLock {
    public static void main(String[] args) {
        AwaitSingal awaitSingal = new AwaitSingal(5);
        Condition a = awaitSingal.newCondition();
        Condition b = awaitSingal.newCondition();
        Condition c = awaitSingal.newCondition();
        new Thread(() -> {
            awaitSingal.print("a",a,b);
        },"t1").start();
        new Thread(() -> {
            awaitSingal.print("b",b,c);
        },"t2").start();
        new Thread(() -> {
            awaitSingal.print("c",c,a);
        },"t3").start();
        // 谁去做第一个叫醒的人？
        Sleeper.sleep(1000);
        awaitSingal.lock();
        try{
            a.signal();
        }finally {
            awaitSingal.unlock();
        }
    }
}

@AllArgsConstructor
class AwaitSingal extends ReentrantLock {
    private int loopNumber;

    /**
     *
     * @param str 要打印的内容
     * @param current 当前要进入哪一间休息室
     * @param next 打印完成后，要唤醒哪一间休息室
     */
    public void print(String str,Condition current,Condition next){
        for(int i =0;i<loopNumber;i++){
            lock();
            try{
                try {
                    current.await();
                    System.out.print(str);
                    next.signal();
                } catch (InterruptedException e) {
                    throw new RuntimeException(e);
                }
            }finally {
                unlock();
            }
        }
    }
}
